home *** CD-ROM | disk | FTP | other *** search
/ PC World 2007 September / PCWorld_2007-09_cd.bin / v cisle / wireshark / wireshark-setup-0.99.6a.exe / dtd_gen.lua < prev    next >
Text File  |  2007-07-09  |  8KB  |  337 lines

  1. -- dtd_gen.lua
  2. --
  3. -- a DTD generator for wireshark
  4. --
  5. -- (c) 2006 Luis E. Garcia Ontanon <luis.ontanon@gmail.com>
  6. --
  7. -- $Id: dtd_gen.lua 19581 2006-10-17 18:26:44Z lego $
  8. -- 
  9. -- Wireshark - Network traffic analyzer
  10. -- By Gerald Combs <gerald@wireshark.org>
  11. -- Copyright 1998 Gerald Combs
  12. --
  13. -- This program is free software; you can redistribute it and/or
  14. -- modify it under the terms of the GNU General Public License
  15. -- as published by the Free Software Foundation; either version 2
  16. -- of the License, or (at your option) any later version.
  17. --
  18. -- This program is distributed in the hope that it will be useful,
  19. -- but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. -- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  21. -- GNU General Public License for more details.
  22. --
  23. -- You should have received a copy of the GNU General Public License
  24. -- along with this program; if not, write to the Free Software
  25. -- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  26.  
  27. if gui_enabled() then
  28.     local xml_fld = Field.new("xml")
  29.  
  30.     local function dtd_generator()
  31.         local displayed = {} -- whether or not a dtd is already displayed
  32.         local dtds = {} -- the dtds
  33.         local changed = {} -- whether or not a dtd has been modified
  34.         local dtd -- the dtd being dealt with
  35.         local dtd_name -- its name
  36.  
  37.         -- we'll tap onto every frame that has xml
  38.  
  39.         local ws = {} -- the windows for each dtd
  40.         local w = TextWindow.new("DTD Generator")
  41.  
  42.         local function help()
  43.             local wh = TextWindow.new("DTD Generator Help")
  44.             -- XXX write help
  45.             wh:set('DTD Generator Help\n')
  46.         end
  47.  
  48.         local function get_dtd_from_xml(text,d,parent)
  49.         -- obtains dtd information from xml
  50.         --   text: xml to be parsed
  51.         --   d: the current dtd (if any)
  52.         --   parent: parent entity (if any)
  53.  
  54.             -- cleanup the text from useless chars
  55.             text = string.gsub(text ,"%s*<%s*","<");
  56.             text = string.gsub(text ,"%s*>%s*",">");
  57.             text = string.gsub(text ,"<%-%-(.-)%-%->"," ");
  58.             text = string.gsub(text ,"%s+"," ");
  59.  
  60.             while true do
  61.                 -- find the first tag
  62.                 local open_tag = string.match(text,"%b<>")
  63.  
  64.                 if open_tag == nil then 
  65.                     -- no more tags, we're done
  66.                     return true
  67.                 end
  68.  
  69.                 local name = string.match(open_tag,"[%w%d_-]+")
  70.                 local this_ent = nil
  71.  
  72.                 if d == nil then
  73.                     -- there's no current dtd, this is entity is it
  74.                     d = dtds[name]
  75.  
  76.                     if d == nil then
  77.                         d = {ents = {}, attrs = {}}
  78.                         dtds[name] = d
  79.                     end
  80.  
  81.                     dtd = d
  82.                     dtd_name = name
  83.                 end
  84.  
  85.                 this_ent = d[name]
  86.  
  87.                 if this_ent == nil then
  88.                     -- no entity by this name in this dtd, create it
  89.                     this_ent = {ents = {}, attrs = {}}
  90.                     d.ents[name] = this_ent
  91.                     changed[dtd_name] = true
  92.                 end
  93.  
  94.                 if parent ~= nil then
  95.                     -- add this entity to its parent
  96.                     parent.ents[name] = 1
  97.                     changed[dtd_name] = true
  98.                 end
  99.                 
  100.                 -- add the attrs to the entity
  101.                 for att in string.gmatch(open_tag, "([%w%d_-]+)%s*=") do
  102.                     if not this_ent.attrs[att] then
  103.                         changed[dtd_name] = true
  104.                         this_ent.attrs[att] = true
  105.                     end
  106.                 end
  107.  
  108.                 if string.match(open_tag,"/>") then
  109.                     -- this tag is "self closed" just remove it and continue
  110.                     text = string.gsub(text,"%b<>","",1)
  111.                 else
  112.                     local close_tag_pat = "</%s*" .. name .. "%s*>"
  113.                     if not string.match(text,close_tag_pat) then return false end
  114.                     local span,left = string.match(text,"%b<>(.-)" .. close_tag_pat .. "(.*)")
  115.  
  116.                     if span ~= nil then
  117.                         -- recurse to find child entities
  118.                         if not get_dtd_from_xml(span,d,this_ent) then
  119.                             return false
  120.                         end
  121.                     end
  122.  
  123.                     -- continue with what's left
  124.                     text = left
  125.                 end
  126.             end
  127.  
  128.             return true
  129.         end
  130.  
  131.         local function entity_tostring(name,entity_data)
  132.         -- name: the name of the entity
  133.         -- entity_data: a table containg the entity data
  134.         -- returns the dtd text for that entity
  135.             local text = ''
  136.             text = text .. '\t<!ELEMENT ' .. name .. '  (' --)
  137.             for e,j in pairs(entity_data.ents) do
  138.                 text = text .. " " .. e .. ' |'
  139.             end
  140.             text = text .. " #PCDATA ) >\n"
  141.             
  142.             text = text .. "\t<!ATTLIST " .. name
  143.             for a,j in pairs(entity_data.attrs) do
  144.                 text = text .. "\n\t\t" .. a .. ' CDTATA #IMPLIED'
  145.             end
  146.             text = text .. " >\n\n"
  147.             
  148.             text = string.gsub(text,"<!ATTLIST " .. name .. " >\n","")
  149.             
  150.             return text
  151.         end
  152.  
  153.         local function dtd_tostring(name,doctype) 
  154.             local text = '<? wireshark:protocol proto_name="' .. name ..'" hierarchy="yes" ?>\n\n'
  155.             local root = doctype.ents[name]
  156.             doctype.ents[name] = nil
  157.  
  158.             text = text .. entity_tostring(name,root)
  159.             
  160.             for n,es in pairs(doctype.ents) do
  161.                 text = text .. entity_tostring(n,es)
  162.             end
  163.  
  164.             doctype.ents[name] = root
  165.  
  166.             return text
  167.         end
  168.  
  169.  
  170.         local function element_body(name,text)
  171.         -- get the entity's children from dtd text
  172.         --    name: the name of the element
  173.         --    text: the list of children
  174.             text = string.gsub(text,"[%s%?%*%#%+%(%)]","")
  175.             text = string.gsub(text,"$","|")
  176.             text = string.gsub(text,
  177.                                "^(.-)|",
  178.                                function(s)
  179.                                     if dtd.ents[name] == nil then
  180.                                        dtd.ents[name] = {ents={},attrs={}}
  181.                                     end
  182.                                
  183.                                     dtd.ents[name].ents[s] = true
  184.                                     return ""
  185.                                end
  186.                                )
  187.             return ''
  188.         end
  189.  
  190.         local function attlist_body(name,text)
  191.         -- get the entity's attributes from dtd text
  192.         --    name: the name of the element
  193.         --    text: the list of attributes
  194.         text = string.gsub(text,"([%w%d_-]+) [A-Z]+ #[A-Z]+",
  195.                                 function(s)
  196.                                     dtd.atts[s] = true
  197.                                     return ""
  198.                                 end
  199.                                 )
  200.             return ''
  201.         end
  202.  
  203.         local function dtd_body(buff)
  204.         -- get the dtd's entities from dtd text
  205.         --    buff: the dtd text
  206.  
  207.             local old_buff = buff
  208.  
  209.             buff = string.gsub(buff,"<!ELEMENT ([%w%d_-]+) (%b())>%s*",element_body)
  210.             buff = string.gsub(buff,"<!ATTLIST ([%w%d_-]+) (.-)>%s*",attlist_body)
  211.         end
  212.  
  213.         local function load_dtd(filename)
  214.             local dtd_filename = USER_DIR ..  "/dtds/" .. filename
  215.             local buff = ''
  216.             local wireshark_info
  217.  
  218.             dtd_name = nil
  219.             dtd = nil
  220.  
  221.             for line in io.lines(dtd_filename) do
  222.                 buff = buff .. line
  223.             end
  224.  
  225.             buff = string.gsub(buff ,"%s*<%!%s*","<!");
  226.             buff = string.gsub(buff ,"%s*>%s*",">");
  227.             buff = string.gsub(buff ,"<!%-%-(.-)%-%->"," ");
  228.             buff = string.gsub(buff ,"%s+"," ");
  229.             buff = string.gsub(buff ,"^%s+","");
  230.  
  231.  
  232.             buff = string.gsub(buff,'(<%?%s*wireshark:protocol%s+.-%s*%?>)',
  233.                                function(s)
  234.                                     wireshark_info = s
  235.                                end
  236.                                )
  237.  
  238.             buff = string.gsub(buff,"^<!DOCTYPE ([%w%d_-]+) (%b[])%s*>",
  239.                                function(name,body) 
  240.                                    dtd = { ents = {}, attrs = {}}
  241.                                    dtd_name = name
  242.                                    
  243.                                    dtds[name] = dtd
  244.                                    
  245.                                    dtd_body(body)
  246.                                    
  247.                                    return ""
  248.                                end
  249.                                )
  250.  
  251.             if not dtd then
  252.                 dtd_body(buff)
  253.             end
  254.             
  255.             if wireshark_info then
  256.                 dtd.wstag = wireshark_info
  257.             end
  258.         end
  259.  
  260.         local function load_dtds()
  261.         -- loads all existing dtds in the user directory
  262.             local dirname = persconffile_path("dtds")
  263.             local status, dir = pcall(Dir.open,dirname,".dtd")
  264.  
  265.              w:set('Loading DTDs from ' .. dirname .. ' \n')
  266.  
  267.             if not status then
  268.                 w:append("Error: could not open the directory" .. dirname .. " , make sure it exists.\n")
  269.                 return
  270.             end
  271.                          
  272.             for dtd_filename in dir do
  273.                 w:append("File:" .. dtd_filename .. "\n")
  274.                 load_dtd(dtd_filename)
  275.             end
  276.  
  277.         end
  278.  
  279.         local function dtd_window(name)
  280.             return function()
  281.                 local wd = TextWindow.new(name .. '.dtd')
  282.                 wd:set(dtd_tostring(name,dtds[name]))
  283.                 wd:set_editable()
  284.  
  285.                 local function save()
  286.                     local file = io.open(persconffile_path("dtds/") .. name .. ".dtd" ,"w")
  287.                     file:write(wd:get_text())
  288.                     file:close()
  289.                 end
  290.                 
  291.                 wd:add_button("Save",save)
  292.             end
  293.         end
  294.  
  295.         local function close()
  296.             if li ~= nil then
  297.                 li:remove()
  298.                 li = nil
  299.             end
  300.         end
  301.  
  302.         w:set_atclose(close)
  303.  
  304.         -- w:add_button("Help",help)
  305.  
  306.         load_dtds()
  307.  
  308.         local li = Listener.new("frame","xml")
  309.  
  310.         w:append('Running')
  311.  
  312.         function li.packet() 
  313.             w:append('.')
  314.             local txt = xml_fld().range:string();
  315.             get_dtd_from_xml(txt)
  316.         end
  317.  
  318.         function li.draw()
  319.  
  320.             for name,j in pairs(changed) do
  321.                 w:append("\n" .. name .. " has changed\n")
  322.                 if not displayed[name] then
  323.                     w:add_button(name,dtd_window(name))
  324.                     displayed[name] = true
  325.                 end
  326.             end
  327.         end
  328.  
  329.         retap_packets()
  330.          w:append(t2s(dtds))
  331.         w:append('\n')
  332.  
  333.     end
  334.  
  335.     register_menu("DTD Generator",dtd_generator,MENU_TOOLS)
  336. end
  337.